package com.faxsun.controller.uc.entity;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.broadleafcommerce.profile.core.domain.Customer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springside.modules.utils.PropertiesLoader;

import weibo4j.org.json.JSONException;
import weibo4j.org.json.JSONObject;

import com.faxsun.profile.core.service.FSThirdPartyCustomerService;

public class WeiXin extends ThirdPartyLoginAbs {
	private static final org.apache.commons.logging.Log log = LogFactory.getLog(WeiXin.class);
	protected static PropertiesLoader propertiesLoader = new PropertiesLoader("classpath:/weixinconfig.properties");

	private static final String APPID = "?appid=" + propertiesLoader.getProperty("AppID");
	private static final String REDIRECT = "&redirect_uri=";
	private static final String URL = propertiesLoader.getProperty("redirect_uri");
	private static final String BIND_URL = propertiesLoader.getProperty("redirect_bind_uri");
	private static final String RESP = "&response_type=code";
	private static final String SCOPE = "&scope=" + propertiesLoader.getProperty("scope");
	private static final String APPENDIX = "#wechat_redirect";
	private static final String GRANT = "&grant_type=authorization_code";
	private static final String SECRET = "&secret=" + propertiesLoader.getProperty("AppSecret");
	private static final String CODE = "&code=";
	private static final String INVALID_CODE = "40029";
	private static final String ERROR_OPEN_ID = "40003";
	private static final String ACCESS_TOKEN = "?access_token=";
	private static final String OPEN_ID = "&openid=";

	@Resource(name = "fsThirdPartyService")
	ThirdPartyLoginServer loginServer;

	@Resource(name = "blThirdPartyCustomerService")
	FSThirdPartyCustomerService fscustomer3thService;

	// 重定向URL，微信返回带code参数的REDIRECT_URI
	@Override
	public void ResponseURL(HttpServletRequest request, HttpServletResponse response) {
		// https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI
		// &response_type=code&scope=SCOPE&state=STATE#wechat_redirect
		String ENCODING = "utf-8";
		String REDIRECT_URI = null;
		try {
			REDIRECT_URI = REDIRECT + URLEncoder.encode(URL, ENCODING);
		} catch (UnsupportedEncodingException e1) {
			log.error(" URLEncoder WeiXin config redirect_URL error ", e1);
			e1.printStackTrace();
		}

		String url = propertiesLoader.getProperty("baseURL") + APPID + REDIRECT_URI + RESP + SCOPE + APPENDIX;
		try {
			response.sendRedirect(url);
		} catch (IOException e) {
			log.error("WeiXin response sendRedirect error ", e);
			e.printStackTrace();
		}

	}

	// 解析出code [and state (state 用于保持请求和回调的状态，授权请求后原样带回给第三方，该参数可用于防止csrf攻击) 本函数未
	// 采用]
	@Override
	public ThirdPartyObj get3rdObj(HttpServletRequest request, HttpServletResponse response, String channel,
			String path) {

		ThirdPartyObj obj3rd = new ThirdPartyObj();
		obj3rd.setChannelId(channel);

		String code = request.getParameter("code");
		if (code == null) {
			log.info("微信未授权");
			return obj3rd;
		}
		obj3rd.setCode(code);

		String accessToken = null;
		String openid = null;
		String nickName = null;
		String unionId = null;
		// get access token by HttpClient
		// https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
		String url = propertiesLoader.getProperty("accessTokenURL") + APPID + SECRET + CODE + code + GRANT;
		String respJson = getHttpResponse(url);

		if (respJson != null) {
			accessToken = getAccessToken(respJson);
			openid = getOpenId(respJson);

		}
		if (accessToken == null || accessToken.equals(INVALID_CODE)) {
			// 我们的网站被CSRF攻击了或者用户取消了授权
			log.info("授权所需code无效");
		} else {
			obj3rd.setAccessToken(accessToken);
			obj3rd.setUid(openid);

			// get nickname
			// GET userInfo:
			// https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID
			String userinfo_url = propertiesLoader.getProperty("userInfoURL") + ACCESS_TOKEN + accessToken + OPEN_ID
					+ openid;
			String resp_json = getHttpResponse(userinfo_url);
			if (resp_json != null) {
				nickName = getNickName(resp_json);
				unionId = getUnionId(respJson);
				obj3rd.setUniondId(unionId);
				obj3rd.setAvatar(getAvatar(resp_json));
			}
			if (nickName == null || nickName.equals(ERROR_OPEN_ID)) {
				log.info("无权获取userinfo或提供的openid错误");
				obj3rd.setNickName("weixin");
			} else {
				obj3rd.setNickName(nickName);
			}
		}

		return obj3rd;
	}

	@Override
	public String login(ThirdPartyObj obj) {
		if (obj.getUid() == null || obj.getUid().isEmpty()) {
			return HOME; // Auth Login Failed! Inform, HOME---> FAIL Page
		}
		if (fscustomer3thService.checkCustomerBy3thUid(obj.getUid())) {
			Customer customer = fscustomer3thService.getCustomerByUid(obj.getUid());
			loginServer.loginDirectly(customer);
			return HOME;
		} else {
			return loginServer.registerThenLogin(obj.getNickName(), obj.getUid(), obj.getChannelId(), obj.getAvatar(),
					obj.getUniondId());
		}
	}

	private String getAccessToken(String resJson) {
		JSONObject jo;
		try {
			jo = new JSONObject(resJson);
			String access_token = jo.getString("access_token");
			if (access_token != null) {
				return access_token;
			} else {
				access_token = jo.getString("errcode");
				return access_token;
			}
		} catch (JSONException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	private String getOpenId(String resJson) {
		JSONObject jo;
		try {
			jo = new JSONObject(resJson);
			String openid = jo.getString("openid");
			if (openid != null) {
				return openid;
			} else {
				openid = jo.getString("errcode");
				return openid;
			}
		} catch (JSONException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	private String getNickName(String resJson) {
		JSONObject jo;
		try {
			jo = new JSONObject(resJson);
			String nickname = jo.getString("nickname");
			if (nickname != null) {
				return nickname;
			} else {
				nickname = jo.getString("errcode");
				return nickname;
			}
		} catch (JSONException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	private String getUnionId(String resJson) {
		JSONObject jo;
		try {
			jo = new JSONObject(resJson);
			String uniondId = jo.getString("unionid");
			if (uniondId != null) {
				return uniondId;
			} else {
				uniondId = jo.getString("errcode");
				return uniondId;
			}
		} catch (JSONException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	private String getAvatar(String resJson) {
		JSONObject jo;
		try {
			jo = new JSONObject(resJson);
			String uniondId = jo.getString("headimgurl");
			if (uniondId != null) {
				return uniondId;
			} else {
				uniondId = jo.getString("errcode");
				return uniondId;
			}
		} catch (JSONException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	private String getHttpResponse(String resUrl) {
		// 创建HttpClient实例
		CloseableHttpClient httpClient = HttpClients.createDefault();
		// HTTP Get请求
		HttpGet httpgets = new HttpGet(resUrl);
		CloseableHttpResponse httpResponse = null;
		// 设置请求和传输超时时间
		Integer timeOut = 2000; // 2 秒 超时
		RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(timeOut)
				.setConnectTimeout(timeOut).setSocketTimeout(timeOut).build();
		httpgets.setConfig(requestConfig);
		HttpEntity entity = null;
		try {
			httpResponse = httpClient.execute(httpgets);
			entity = httpResponse.getEntity();
			String response = EntityUtils.toString(entity, "UTF-8");
			return response;
		} catch (ClientProtocolException e) {
			log.error("http protocol error：" + e.getMessage());
		} catch (IOException e) {
			log.error("http IO error：" + e.getMessage());
		} catch (Exception e) {
			log.error("httpException：" + e.getMessage());
		} finally {
			try {
				httpResponse.close();
			} catch (IOException e) {
				log.error("http IO error ：" + e.getMessage());
			} catch (NullPointerException e) {
				log.error("http NullPointer error：" + e.getMessage());
			}
		}
		return null;
	}

	@Override
	public void bindRequestUrl(HttpServletRequest request, HttpServletResponse response) {

		// https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=BIND_URI
		// &response_type=code&scope=SCOPE&state=STATE#wechat_redirect
		String ENCODING = "utf-8";
		String REDIRECT_URI = null;
		try {
			String bindProcessUrl = BIND_URL + "?redirect_uri=" + request.getHeader("Referer");
			REDIRECT_URI = REDIRECT + URLEncoder.encode(bindProcessUrl, ENCODING);
		} catch (UnsupportedEncodingException e1) {
			log.error(" URLEncoder WeiXin config redirect_URL error ", e1);
			e1.printStackTrace();
		}

		String url = propertiesLoader.getProperty("baseURL") + APPID + REDIRECT_URI + RESP + SCOPE + APPENDIX;
		try {
			response.sendRedirect(url);
		} catch (IOException e) {
			log.error("WeiXin response sendRedirect error ", e);
			e.printStackTrace();
		}
	}

}
